package com.wyvoid.forum.web.listener;

import com.wyvoid.forum.Constant;
import com.wyvoid.forum.domain.SessionUser;
import com.wyvoid.forum.util.ForumUtil;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.util.Date;
import java.util.HashMap;


/**
 * UserCounterListener class used to count the current number
 * of active users for the applications.  Does this by counting
 * how many user objects are stuffed into the session.  It Also grabs
 * these users and exposes them in the servlet context.
 *
 * @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a>
 * @web.listener
 */
public class UserCounterListener implements ServletContextListener,
        HttpSessionAttributeListener, HttpSessionListener {
    public static final String COUNT_KEY = "userCounter";
    public static final String USERS_KEY = "userNames";
    public static final String TOTAL_COUNT_KEY = "totalCounter";
    private final transient Log log = LogFactory.getLog(UserCounterListener.class);
    private transient ServletContext servletContext;
    private int userCounter;
    public static HashMap<Long,SessionUser> users=new HashMap<Long,SessionUser>();
    private int totalCounter;

    public synchronized void contextInitialized(ServletContextEvent sce) {
        servletContext = sce.getServletContext();
        servletContext.setAttribute((COUNT_KEY), Integer.toString(userCounter));
        servletContext.setAttribute((TOTAL_COUNT_KEY), Integer.toString(totalCounter));
    }

    public synchronized void contextDestroyed(ServletContextEvent event) {
        servletContext = null;
        users = null;
        userCounter = 0;
        totalCounter = 0;
    }

    synchronized void incrementUserCounter() {
        userCounter =
                Integer.parseInt((String) servletContext.getAttribute(COUNT_KEY));
        userCounter++;
        servletContext.setAttribute(COUNT_KEY, Integer.toString(userCounter));

        if (log.isDebugEnabled()) {
            log.debug("User Count: " + userCounter);
        }
    }

    synchronized void decrementUserCounter() {
        int counter =
                Integer.parseInt((String) servletContext.getAttribute(COUNT_KEY));
        counter--;

        if (counter < 0) {
            counter = 0;
        }

        servletContext.setAttribute(COUNT_KEY, Integer.toString(counter));

        if (log.isDebugEnabled()) {
            log.debug("User Count: " + counter);
        }
    }

    @SuppressWarnings({"unchecked"})
    synchronized void addUsername(Object user) {
        users = (HashMap) servletContext.getAttribute(USERS_KEY);

        SessionUser sessionUser= (SessionUser) user;
        if (users == null) {
            users = new HashMap<Long,SessionUser>();
        }


        if (log.isDebugEnabled()) {
            if (users.containsKey(sessionUser.getId())) {
                log.debug("User already logged in, adding anyway...");
            }
        }

        users.put(sessionUser.getId(),sessionUser);
        servletContext.setAttribute(USERS_KEY, users);
        incrementUserCounter();
    }

    @SuppressWarnings({"unchecked"})
    synchronized void removeUsername(Object user) {
        users = (HashMap) servletContext.getAttribute(USERS_KEY);

        SessionUser sessionUser= (SessionUser) user;
        if (users != null) {
            users.remove(sessionUser.getId());
        }

        servletContext.setAttribute(USERS_KEY, users);
        decrementUserCounter();
    }

    /**
     * This method is designed to catch when user's login and record their name
     *
     * @see javax.servlet.http.HttpSessionAttributeListener#attributeAdded(javax.servlet.http.HttpSessionBindingEvent)
     */
    public void attributeAdded(HttpSessionBindingEvent event) {
        if (event.getName().equals(Constant.SESSION_USER_KEY)) {
            addUsername(event.getValue());
        }
    }

    /**
     * When user's logout, remove their name from the hashMap
     *
     * @see javax.servlet.http.HttpSessionAttributeListener#attributeRemoved(javax.servlet.http.HttpSessionBindingEvent)
     */
    public void attributeRemoved(HttpSessionBindingEvent event) {
        if (event.getName().equals(Constant.SESSION_USER_KEY)) {
            removeUsername(event.getValue());
        }
    }

    /**
     * @see javax.servlet.http.HttpSessionAttributeListener#attributeReplaced(javax.servlet.http.HttpSessionBindingEvent)
     */
    public void attributeReplaced(HttpSessionBindingEvent event) {
        // I don't really care if the user changes their information
    }

    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        totalCounter =
                Integer.parseInt((String) servletContext.getAttribute(TOTAL_COUNT_KEY));
        totalCounter++;
        servletContext.setAttribute(TOTAL_COUNT_KEY, Integer.toString(totalCounter));

        if (totalCounter > (Integer.parseInt((String)ForumUtil.settings.get(ForumUtil.HIGHESTTOTALCOUNTER)))) {
            ForumUtil.putSettingsAndToDB(ForumUtil.HIGHESTTOTALCOUNTER, totalCounter+"");
            String dateStr= DateFormatUtils.format(new Date(), "yyyy-MM-dd");
            ForumUtil.putSettingsAndToDB(ForumUtil.HIGNESTTOTALCOUNTERTIME,dateStr);
        }
        if (log.isDebugEnabled()) {
            log.debug("Total User Count: " + totalCounter);
        }
    }

    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        int counter =
                Integer.parseInt((String) servletContext.getAttribute(TOTAL_COUNT_KEY));
        counter--;

        if (counter < 0) {
            counter = 0;
        }

        servletContext.setAttribute(TOTAL_COUNT_KEY, Integer.toString(counter));

        if (log.isDebugEnabled()) {
            log.debug("Total User Count: " + counter);
        }
    }
}
